// Object.cpp - an object which has an ID and position
//
// Nick Kitten
// 2009

#include "Object.h"

////////////////////////////////////////////
// constructor
Object::Object()
{
}

Object::Object(int id, float x, float y, float z)
: ID( id ), position( x, y, z )
{
}

////////////////////////////////////////////
// destructor
Object::~Object()
{
}

////////////////////////////////////////////
// return the object's ID
int 
Object::getID() const
{
	return this->ID;
}

///////////////////////////////////////////////////////
// return a copy of the object's positition
Triple 
Object::getPosition() const
{
	return this->position;
}
///////////////////////////////////////////////////////
// return the x coordinate of the position
float 
Object::getPosX() const
{
	return this->position.x;
}
///////////////////////////////////////////////////////
// return the y coordinate of the position
float 
Object::getPosY() const
{
	return this->position.y;
}

///////////////////////////////////////////////////////
// return the z coordinate of the position
float 
Object::getPosZ() const
{
	return this->position.z;
}

///////////////////////////////////////////////////////
// set the object's current position
void 
Object::setPosition(float x, float y, float z)
{
	// Children
	if( ! positionChildren.empty() )
	{
		// Move children by the same amount this object is being moved
		// from its previous location.
		float dx, dy, dz;
		dx = x - this->getPosX();
		dy = y - this->getPosY();
		dz = z - this->getPosZ();

		list<PositionConstraint>::iterator child = positionChildren.begin();
		Triple newPos;

		while( child != positionChildren.end() )
		{
			newPos = child->obj->getPosition();
			
			// X axis constraint exists
			if( child->axes.find( 'x' ) != child->axes.end() )
			{
				newPos.x += dx;
			}
			// Y axis constraint exists
			if( child->axes.find( 'y' ) != child->axes.end() )
			{
				newPos.y += dy;
			}
			// Z axis constraint exists
			if( child->axes.find( 'z' ) != child->axes.end() )
			{
				newPos.z += dz;
			}

			child->obj->setPosition( newPos );

			child++;
		}
	}

	this->position.x = x;
	this->position.y = y;
	this->position.z = z;
}

void Object::constrainToPosition( Object * child, std::string axes )
{
	list<PositionConstraint>::iterator elem, oldChild = positionChildren.end();

	for( elem = positionChildren.begin(); elem != positionChildren.end(); elem++ )
	{
		if( *( elem->obj ) == *( child ) )
		{
			oldChild = elem;
			break;
		}
	}

	// make sure input string is in uniform case, since the set of axes doesn't contain duplicates
	axes = StringToLower( axes );
	
	// the child was not found in the list, so it had no previous constraints
	if( ! ( oldChild == positionChildren.end() ) || positionChildren.empty() )
	{
		PositionConstraint newChild;
		newChild.obj = child;
		// Insert all listed axes into the set of constrained axes
		for( int i = 0; i < axes.length(); i++ )
		{
			newChild.axes.insert( axes[i] );
		}
		positionChildren.push_front( newChild );
	}
	else
	{
		for( int i = 0; i < axes.length(); i++ )
		{
			oldChild->axes.insert( axes[i] );
		}
	}

}

// Removes position constraints on an object, returning "true" if something was removed,
// and "false" if the specified child object was not found.
bool Object::removePositionConstraint( Object *child, std::string axes )
{
	// make sure input string is in uniform case, so the set of axes doesn't contain duplicates
	axes = StringToLower( axes );

	list<PositionConstraint>::iterator elem, oldChild = positionChildren.end();

	for( elem = positionChildren.begin(); elem != positionChildren.end(); elem++ )
	{
		// Go through the list of children, and if the child is found, remove the
		// specified axes from those being constrained.
		if( *( elem->obj ) == *( child ) )
		{
			oldChild = elem;

			for( int i = 0; i < axes.length(); i++ )
			{
				oldChild->axes.erase( axes[i] );
			}

			// If there are no remaining constraints, remove from the list
			if( oldChild->axes.empty() )
			{
				positionChildren.erase( elem );
			}

			return true;
		}
	}

	return false;

}
